#include <sys/types.h>         
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include "stdNetWork.h"
#include <json-c/json.h>
#include "commonTool.h"
#include "businessFunc.h"
#include "stdShared.h"
#include <pthread.h>
#include "doubleLinkList.h"
#include "stdDataBase.h"
#include "threadpool.h"

#define SERVER_PORT     8080
//#define BUFFER_SIZE     256

/* 心跳检测 - 检测时间间隔 */
#define CHECK_INTERVAL        5

#define MIN_THREAD_NUM        5
#define MAX_THREAD_NUM        20
#define MAX_QUEUE_SIZE        50


DoubleLinkList * g_list = NULL;


static void * thread_conn(void * arg)
{
    /* 线程分离 */
    pthread_detach(pthread_self());

    /* 通信句柄 */
    int connfd = *(int *)arg;

    while (1)
    {
        /* 服务器接收客户端的信息, 并做出反馈 */
        
        char readBuffer[BUFFER_SIZE] = { 0 };
        int readBytes = 0;

        char writeBuffer[BUFFER_SIZE] = { 0 };
        int writeBytes = 0;

    
        while (1)
        {
            /* json类型字符串 {} */
            
            readBytes = read(connfd, (void *)&readBuffer, sizeof(readBuffer) - 1);
            if (readBytes < 0)
            {
                /* 读出错 */
                perror("read error");
                break;
            }
            else if (readBytes == 0)
            {
                /* 这边读到的字节数为0, 说明什么? */
                printf("客户端下线\n");

                /* connfd <-> 用户名 (所有的好友 ) */
                break;
            }
            else
            {
                printf("readBuffer:%s\n", readBuffer);

                enum FUNCTION_OPTION choice = EXITS;
                parseBusinessOption(readBuffer, &choice);
                switch (choice)
                {
                case REGIS:
                    {
                        chatRoomServerRegister(connfd, readBuffer);
                    }
                    break;
                case LOGIN:
                    {
                        UserInfo *info = (UserInfo *)readBuffer;
                        chatRoomServerLogIn(connfd, info);

                        
                    }
                    break;
                case PRI_CHAT:
                    {
                        MessageInfo *info = (MessageInfo *)readBuffer;
                        chatRoomServerPriChat(connfd, info);
                    }
                    break;
                case GROUP_CHAT:
                    {
                        MessageInfo *info = (MessageInfo *)readBuffer;
                        chatRoomServerSharedChat(connfd, info);
                    }
                    break;
                case HEART_CHECK:
                    {
                        /* 心跳 */
                        /* 暂定 alarm 函数 */
                    }
                default:
                    break;
                }
            }
        }
    }
    /* 回收资源 */
    close(connfd);
}   

/* 每个用户登陆成功之后, */
/* 心跳检测 - 检测在线列表是否是离线状态 */
static void * thread_refresh(void * arg)
{
    /* 线程分离 */
    pthread_detach(pthread_self());

    while (true)
    {
        /* 检测时间间隔 */
        sleep(CHECK_INTERVAL);

        /* 是否需要加锁 ? */

        /* 获取在线用户人数 */
        int livedNums;
        DoubleLinkListGetSize(g_list, &livedNums);


        UserToConnfd *mapInfo = NULL;
        
        enum FUNCTION_OPTION code = HEART_CHECK;
        for (int idx = 0; idx < livedNums; idx++)
        {
            DoubleLinkListGetAppointPositionData(g_list, idx, &mapInfo);
            write(mapInfo->connfd, &code, sizeof(int));
        }
    }

    return NULL;
}

int main()
{
    int ret = 0;

    /* 初始化线程池 */
    ThreadPool pool;
    ret = threadPoolInit(&pool, MIN_THREAD_NUM, MAX_THREAD_NUM, MAX_QUEUE_SIZE);
    if (ret != 0)
    {
        perror("thread pool init error");
        exit(-1);
    }

    /* 联网 */
    int sockfd = socketListen(SERVER_PORT);
    if (sockfd == -1)
    {
        perror("socketListen error");
        exit(-1);
    }

    /* 链表初始化 用于维护用户在线列表 */
    DoubleLinkListInit(&g_list);


    /* 负责心跳检测的线程 主要负责刷新业务 */
    pthread_t tid;
    ret = pthread_create(tid, NULL, thread_refresh, NULL);
    if (ret == -1)
    {
        perror("thread create error");
        exit(-1);
    }

    while (true)
    {
        /* 服务器365天 24小时 */
        /* accept的返回值是和【客户端通信】的文件描述符 */
        int connfd = accept(sockfd, NULL, NULL);
        if (connfd == -1)
        {
            perror("accept error");
            exit(-1);
        }
        /* 程序执行到这个地方, 意味着有新的客户端与服务器连接 */
        printf("connfd is %d\n", connfd);

        /* 将任务添加到任务队列中 */
        threadPoolAdd(&pool, thread_conn, (void *)&connfd);


        /*  warning: 
            提示: 这边的延时为了 connfd 的地址能够被线程正确的取到, 
                不然栈空间地址释放线程 地址会取到奇怪的值. 
        */
        usleep(1000);
    }

    /* 回收资源 */
    close(sockfd);
    return 0;
}